package com.lcf.app.awss3.service;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.*;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.http.MediaTypeFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * https://docs.aws.amazon.com/AmazonS3/latest/userguide/mpu-upload-object.html
 */
@Service
@RequiredArgsConstructor
public class AmazonS3Service {

    private static final String bucketName = "amazons3-bucket";

    private final AmazonS3 amazonS3;

    @PostConstruct
    public void initBucket() {
        createBucket(bucketName);
    }

    /**
     * 上传文件
     *
     * @param multipartFile
     * @return
     * @throws IOException
     */
    public String putObject(MultipartFile multipartFile) throws IOException {
        String key = DateUtil.format(LocalDateTime.now(), "yyyy/MM/dd/") +
                IdUtil.fastSimpleUUID() + "." +
                FileUtil.getSuffix(multipartFile.getOriginalFilename());
        ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setContentLength(multipartFile.getSize());
        amazonS3.putObject(
                bucketName,
                key,
                multipartFile.getInputStream(),
                objectMetadata
        );
        return key;
    }

    /**
     * 下载文件
     *
     * @param key
     * @return
     */
    public S3ObjectInputStream getObject(String key) {
        S3Object object = amazonS3.getObject(bucketName, key);
        return object.getObjectContent();
    }

    /**
     * 创建桶
     *
     * @param bucketName
     */
    public void createBucket(String bucketName) {
        if (!amazonS3.doesBucketExistV2(bucketName)) { // 不存在则创建
            amazonS3.createBucket(bucketName);
        }
    }


    private static final Map<String, String> uploadIds = new HashMap<>();

    /**
     * 初始化分片上传
     *
     * @param fileName
     * @return
     */
    public String initUpload(String fileName, Map<String, String> userMetadata) {
        // 初始化分片上传
        ObjectMetadata objectMetadata = new ObjectMetadata();
        if (userMetadata != null) {
            userMetadata.forEach(objectMetadata::addUserMetadata); // 描述数据,存进去之后可以后边获取。
        }
        objectMetadata.setExpirationTime(new Date(System.currentTimeMillis() + 1000 * 60 * 10)); // 10分钟
        String contentType = MediaTypeFactory.getMediaType(fileName).orElse(MediaType.APPLICATION_OCTET_STREAM).toString();
        objectMetadata.setContentType(contentType);
        InitiateMultipartUploadRequest initiateMultipartUploadRequest =
                new InitiateMultipartUploadRequest(bucketName, fileName).withObjectMetadata(objectMetadata);
        InitiateMultipartUploadResult initiateMultipartUploadResult = amazonS3.initiateMultipartUpload(initiateMultipartUploadRequest);
        String uploadId = initiateMultipartUploadResult.getUploadId();
        uploadIds.put(uploadId, fileName); // 保存uploadId 和 key 的关联关系。
        Console.log("uploadIds : {}", JSON.toJSONString(uploadIds));
        return uploadId; //
    }

    /**
     * 分片上传
     *
     * @param file
     * @param uploadId
     */
    public void uploadPart(MultipartFile file, String uploadId, int number) throws IOException {
        UploadPartRequest uploadRequest = new UploadPartRequest()
                .withBucketName(bucketName)
                .withKey(uploadIds.get(uploadId))
                .withUploadId(uploadId)
                .withPartNumber(number)
                .withInputStream(file.getInputStream())
                .withPartSize(file.getSize());
        UploadPartResult uploadPartResult = amazonS3.uploadPart(uploadRequest);
        Console.log("uploadPartResult: {}", JSON.toJSONString(uploadPartResult));
    }

    /**
     * 合并分片上传
     *
     * @param uploadId
     */
    public void completeUpload(String uploadId) {
        // 查询分片数据
        PartListing listParts = amazonS3.listParts(
                new ListPartsRequest(bucketName, uploadIds.get(uploadId), uploadId));
        List<PartETag> tagList = listParts.getParts()
                .stream()
                .map(v -> new PartETag(v.getPartNumber(), v.getETag())).collect(Collectors.toList());
        // 分片上传完成后任务完成接口
        amazonS3.completeMultipartUpload(new CompleteMultipartUploadRequest()
                .withBucketName(bucketName)
                .withKey(uploadIds.get(uploadId))
                .withPartETags(tagList)
                .withUploadId(uploadId));
    }
}
